# -*- coding: utf-8 -*-
'''
Created on 2013-4-11

@author: cl.lam
'''
from datetime import datetime as dt
from werkzeug.exceptions import abort
import flask
import traceback
from flask import current_app as app
from flask import g, render_template, flash, session, redirect, url_for, request, request_finished
from flask.blueprints import Blueprint
from sqlalchemy.sql.expression import desc, and_
from flask.helpers import jsonify

from sys2do.views import BasicView
from sys2do.util.decorator import templated, activetab, mypaginate, \
    allPermission
from sys2do.util.logic_helper import getCurrentShopID, checkLogin, \
    getCurrentUserID, getCurrentShopProfile, makeUpdateLog, checkUpdate
from sys2do.constant import *

from sys2do.util.common import _gld, _gp, _g, multiupload
from sys2do.model import db, Product, qry, SysLog, SysFile, InventoryLocation, \
    PO, InventoryProduct, PODtl, InventoryNote, \
    InventoryNoteDtl, FinNote, FinNoteDtl, ItemBalance
from sys2do.util.wt_helper import MyDateField

from sys2do.util.barcode_helper import genBarcodeFile
from sys2do.util.exception import MoreThanStockExp


__all__ = ['bpPrh']


bpPrh = Blueprint( 'bpPrh', __name__, )

@bpPrh.before_request
def _b():
    return checkLogin()


class PurchaseView( BasicView ):

    template_folder = 'prh'


    @templated( "index.html" )
    @activetab( TAB_HOME )
    @mypaginate( 'result' )
    @allPermission( ['PURCHASE_VIEW'] )
    def index( self ):

        if request.method == 'POST':
            form = SrhForm( request.form )
            session[url_for( '.view' )] = form
        else:
            form = session.get( url_for( '.view' ), SrhForm( request.form ) )
        form.url = url_for( '.view' )
        spobj = getCurrentShopProfile()

        cds = [ PO.active == 0, PO.shopID == spobj.shopID ]
        if form.no.data : cds.append( PO.no.like( '%%%s%%' % form.no.data ) )
        if form.status.data and form.status.data != 'None' :  cds.append( PO.status == form.status.data )
        if form.createTimeFrom.data : cds.append( PO.createTime > form.createTimeFrom.data )
        if form.createTimeTo.data : cds.append( PO.createTime < form.createTimeTo.data )
        result = PO.iall( conditions = cds, order_by = desc( PO.createTime ) )

        return {'form' : form , 'result' : result}



    @templated( "add.html" )
    @allPermission( ['PURCHASE_CREATE'] )
    def add( self ):
        sid = getCurrentShopID()
        if request.method != 'POST':
            return {}
        try:
            params = _gld( 'supplierID', 'att', 'tel', 'mobile', 'remark' )
            params['shopID'] = sid
            params['createById'] = getCurrentUserID()
            params['updateById'] = getCurrentUserID()
            params['attachment'] = multiupload()

            hdr = PO.create( params )
            db.add( hdr )
            amount, realAmount = 0, 0
            for ( k, v ) in _gp( "product_" ):
                if not v : continue
#                 pid = k.split( "_" )[1]
                pid = v
                qty = int( _g( "qty_" + pid ) or 0 )
                pPrice = float( _g( 'pPrice_%s' % pid ) or 0 )
                realPrice = float( _g( 'realPrice_%s' % pid ) or 0 )
                rm = _g( 'remark_%s' % pid )
                dtl = PODtl( hdr = hdr, pdtID = pid, qty = qty, price = pPrice, discounts = 1, realPrice = realPrice, remark = rm )
                amount += pPrice * qty
                realAmount += realPrice * qty
                dtl.copyPdtInfo( Product.get( pid ) )
                db.add( dtl )

            hdr.amount = amount
            hdr.realAmount = realAmount
            db.flush()
            db.add( SysLog( refClz = hdr.__class__.__name__, type = LOG_TYPE_CREATE, refID = hdr.id, ) )
            db.commit()
            flash( MSG_SAVE_SUCC, MESSAGE_INFO )
        except:
            self._error( traceback.format_exc() )
            db.rollback()
            flash( MSG_SERVER_ERROR, MESSAGE_ERROR )
            return redirect( url_for( '.view' ) )
        else:
            return redirect( url_for( '.view', action = 'view', id = hdr.id ) )


    @templated( 'view.html' )
    def view( self ):
        obj = PO.get( _g( 'id' ) )
        return {'obj' : obj}


    @templated( 'update.html' )
    def update( self ):
        pid = _g( 'id' )
        if not pid :
            flash( MSG_NO_ID_SUPPLIED, MESSAGE_ERROR )
            return redirect( url_for( ".view" ) )

        obj = PO.get( pid )
        if not obj :
            flash( MSG_RECORD_NOT_EXIST, MESSAGE_ERROR )
            return redirect( url_for( ".view" ) )

        if request.method != 'POST': return {'obj' : obj}

        try:
            oldCopy = obj.serialize()
            extLog = []

            params = _gld( 'supplierID', 'att', 'tel', 'mobile', 'remark' )
            obj.update( params )
            obj.updateTime = dt.now()
            obj.updateById = getCurrentUserID()

            oldaset = set( map( lambda v : unicode( v.id ), obj.attachment ) )
            newaset = set( filter( bool, _g( 'attachment', '' ).split( "|" ) ) )
            deltedAtm = oldaset.difference( newaset )
            if deltedAtm :
                delAtms = qry( SysFile ).filter( SysFile.id.in_( list( deltedAtm ) ) )
                extLog.extend( [u'删除附件[%s]。' % da.name for da in delAtms] )

            if newaset : obj.attachment = sorted( list( newaset ) ) + multiupload()
            else : obj.attachment = multiupload()

            amount, realAmount = 0, 0

            for d in obj.dtls:
                if not _g( 'oldproduct_%s' % d.id ) :
                    extLog.append( u'删除商品[%s],数量[%s],备注[%s]。' % ( d.pdtname, d.qty, d.remark ) )
                    d.active = 1
                oldDtl = d.serialize()
                d.price = _g( 'oldpPrice_%s' % d.id ) or 0
                d.realPrice = _g( 'oldrealPrice_%s' % d.id ) or 0
                d.qty = _g( 'oldqty_%s' % d.id ) or 0
                d.remark = _g( 'oldremark_%s' % d.id )
                amount += float( d.price ) * int( d.qty )
                realAmount += float( d.realPrice ) * int( d.qty )
                newDtl = d.serialize()

                tmpLog = checkUpdate( oldDtl, newDtl )
                if tmpLog : extLog.extend( [u'修改商品 [%s]：' % d.pdtname, ] + tmpLog )
                d.copyPdtInfo( d.pdt )

            for ( k, v ) in _gp( "product_" ):
                if not v : continue
                pid = v
                qty = int( _g( "qty_" + pid ) or 0 )
                pPrice = float( _g( 'pPrice_%s' % pid ) or 0 )
                realPrice = float( _g( 'realPrice_%s' % pid ) or 0 )
                rm = _g( 'remark_%s' % pid )
                dtl = PODtl( hdr = obj, pdtID = pid, qty = qty, price = pPrice, discounts = 1, realPrice = realPrice, remark = rm )
                amount += pPrice * qty
                realAmount += realPrice * qty
                dtl.copyPdtInfo( Product.get( pid ) )    # copy the product info the dtl
                db.add( dtl )

            obj.amount = amount
            obj.realAmount = realAmount

            newCopy = obj.serialize()
            makeUpdateLog( obj, oldCopy, newCopy, extLog )
            flash( MSG_SAVE_SUCC, MESSAGE_INFO )
            db.commit()
        except:
            self._error( traceback.format_exc() )
            db.rollback()
            flash( MSG_SERVER_ERROR, MESSAGE_ERROR )
        return redirect( url_for( ".view", action = 'view', id = obj.id ) )



    @allPermission( ['PURCHASE_APPROVE'] )
    def app( self ):
        try:
            spro = getCurrentShopProfile()
            prhivt = InventoryLocation.getPurchaseIvt()
            obj = PO.get( _g( 'id' ) )
            obj.status = PO_APPROVE
            # create inventory in note
            notehdr = InventoryNote.create( dict( shopID = spro.shopID, direction = IVTNT_IN,
                                                  refer = obj.no, ivtID = prhivt.id, status = IVTNT_NEW ) )
            notehdr.comeFrom = ( obj, obj.id )
            # create fin in note
            finhdr = FinNote.create( {'direction' : FIN_OUT, 'amount' : obj.realAmount,
                                     'refer' : obj.no, 'status' : FIN_NEW , 'accountID' : None,
                                     'shopID' : spro.shopID , 'issueTo' : unicode( obj.supplier ),
                                     'issueFrom' : unicode( obj.supplier.fullName ),
                                     'currencyID' : obj.currencyID, } )
            finhdr.comeFrom = ( obj, obj.id )
            db.add_all( [notehdr, finhdr, ] )
            for d in obj.dtls:
                ivtntDtl = InventoryNoteDtl.create( dict( hdr = notehdr, pdtID = d.pdtID, qty = d.qty, sIvtLtnID = prhivt.id, dIvtLtnID = spro.inventoryID ) )
                ivtntDtl.copyPdtInfo( d.pdt )
                db.add( ivtntDtl )
                db.add( FinNoteDtl.create( {'hdr' : finhdr, 'itemName' : d.pdt.name, 'desc' : d.pdt.makeDesc() , 'refer' : d.id,
                                            'price' : d.realPrice, 'qty' : d.qty, 'amount' : d.qty * d.realPrice, } ) )

                #===============================================================
                # 1. add the qty to the pruchase inventory,
                # 2. to move the product from purchase inventory to the shop's
                #    root inventory
                #===============================================================
                InventoryProduct.addOrUpdate( prhivt.id, d.pdtID, d.qty, 0, 0 )
#                 InventoryProduct.goingToMove( ivtntDtl.sIvtLtnID, ivtntDtl.dIvtLtnID, d.pdtID, d.qty )

                # create item and log the purchase price
                items = d.pdt.genItem( d.qty )
                for item in items :
                    item.pPrice, item.ivtID = d.realPrice, prhivt.id
                    db.add( ItemBalance( item = item, pPrice = d.realPrice, pRefer = obj.no ) )

            db.flush()
            # add the log
            db.add( SysLog.create( dict( refClz = obj.__class__.__name__, type = LOG_TYPE_APPROVE, refID = obj.id ) ) )
            db.add( SysLog.create( dict( refClz = notehdr.__class__.__name__, type = LOG_TYPE_CREATE, refID = notehdr.id ) ) )
            db.add( SysLog.create( dict( refClz = finhdr.__class__.__name__, type = LOG_TYPE_CREATE, refID = finhdr.id ) ) )
            db.commit()
            flash( MSG_UPDATE_SUCC, MESSAGE_INFO )
        except:
            self._error( traceback.format_exc() )
            db.rollback()
            flash( MSG_SERVER_ERROR, MESSAGE_ERROR )
        return redirect( url_for( '.view' ) )


    @allPermission( ['PURCHASE_DEL'] )
    def delete( self ):
        try:
            obj = PO.get( _g( 'id' ) )
            if obj.status == PO_APPROVE:
                flash( MSG_NO_SUCH_ACTION, MESSAGE_ERROR )
            else:
                obj.active = INACTIVE
                db.add( SysLog.create( dict( refClz = obj.__class__.__name__, type = LOG_TYPE_DEL, refID = obj.id, ) ) )
                db.commit()
                flash( MSG_UPDATE_SUCC, MESSAGE_INFO )
        except:
            self._error( traceback.format_exc() )
            db.rollback()
            flash( MSG_SERVER_ERROR, MESSAGE_ERROR )
        return redirect( url_for( '.view' ) )



    @templated( 'view_log.html' )
    def viewLog( self ):
        id = _g( 'id' )
        if not id : abort( 404 )
        obj = PO.get( id )
        if not obj : abort( 404 )
        return {'obj' : obj}


    @templated( 'label.html' )
    def printLabel( self ):
        pid = _g( 'id' )
        if not pid :
            flash( MSG_NOT_ENOUGH_PARAMS, MESSAGE_ERROR )
            return redirect( url_for( '.view' ) )
        obj = Product.get( pid )
        if obj is None :
            flash( MSG_RECORD_NOT_EXIST, MESSAGE_ERROR )
            return redirect( url_for( '.view' ) )
        return {'obj' : obj}


    def ajaxSrhPdt( self ):
        f = _g( 'f' )
        q = _g( 'q' )

        if not f : return jsonify( {'code' : 1, 'msg' : MSG_NOT_ENOUGH_PARAMS, 'data' : []} )
        try:
            cs = [Product.active == 0, ]
            if q:  cs.append( getattr( Product, f ).like( '%%%s%%' % q ) )

            return jsonify( {
                            'code' : 0 , 'msg' : 'OK',
                            'data' : [p.toJson() for p in Product.all( conditions = cs, order_by = Product.name )]
                            } )
        except:
            self._error( traceback.format_exc() )
            return jsonify( {'code' : 1, 'msg' : MSG_SERVER_ERROR} )


bpPrh.add_url_rule( '/', view_func = PurchaseView.as_view( 'view' ), defaults = {'action':'index'} )
bpPrh.add_url_rule( '/<action>', view_func = PurchaseView.as_view( 'view' ) )



#===============================================================================
# form class
#===============================================================================

from wtforms import Form, TextField, SelectField

class SrhForm( Form ):
    no = TextField( u'系统编号', {'class_' :'form-control'} )
    status = SelectField( u'状态', choices = [( '', '' ), ( unicode( PO_NEW ), u'新建' ), ( unicode( PO_APPROVE ), u'批准' ), ( unicode( PO_DISAPPROVE ), u'拒绝' )] )
    creator = TextField( u'创建人', )
    createTimeFrom = MyDateField( u'创建时间(开始)', )
    createTimeTo = MyDateField( u'创建时间(结束)' )
